Preparing R Studio


Install Libraries

library(vosonSML)
library(tidyverse)
library(tidytext)
library(quanteda)
library(syuzhet)
library(reshape2)
library(lda)
library(jsonlite)
library(stringr)
library(tm)
library(rtweet)
library(ggplot2)
library(lubridate)
library(hms)
library(caTools)
library(caret)
library(e1071)
library(rpart)
library(rpart.plot)
library(party)
library(forecast)
library(arules)

AWS


RDBS Connection

host = "text-analysis.cpkypoj1gkct.us-east-1.rds.amazonaws.com"
port = 3306
user = "rvillarreal"
password = "x10809877"

my_instance = DBI :: dbConnect(
  RMySQL :: MySQL(),
  host = host,
  port = port,
  user = user,
  password = password
)

Creating Database

dbSendQuery(my_instance, "CREATE DATABASE TWEETS")

Database Connection

dbname = "TWEETS"

con = DBI :: dbConnect(
  RMySQL :: MySQL(),
  dbname = dbname,
  host = host,
  port = port,
  user = user,
  password = password
)

Twitter


API Connection

consumer_key <- "R7gjfyZMLN2vK6iFlQf2hhCPw"
consumer_secret <- "Zr5BqyPKPzkfMpAi3HijHk5HNFgNffvisPDAiSwd9fLyDKB3Il"
access_token <- "1326312317705916416-6estSlWdrKq26zO5blGoD1OaOVfLCV"
access_secret <- "Jh4UgN83EZWV4wLQmjkJZkKdZz0ByNe5kl3q1qHowb81L"

twitter_token <- create_token(
  app = "Programming_Data_Analytics",
  consumer_key = consumer_key,
  consumer_secret = consumer_secret,
  access_token = access_token,
  access_secret = access_secret
)

setup_twitter_oauth(consumer_key, consumer_secret, access_token, access_secret)
[1] "Using direct authentication"

Tweets Extraction and CSV

#messi_tweets9 <- search_tweets("messi OR MESSI OR Messi", n = 18000, lang = "en", include_rts = F)

messi_tweets_final <- data.frame(unique(rbind(messi_tweets3, messi_tweets2, messi_tweets, messi_tweets4, messi_tweets5, messi_tweets6, messi_tweets7, messi_tweets8, messi_tweets9)))

messi_tweets_final <- messi_tweets_final %>%
                      separate(created_at, into = c("Date", "Time"), sep = " ", convert = TRUE)

messi_tweets_final$Time <- as.hms(messi_tweets_final$Time)
messi_tweets_final$Date <- as.Date(messi_tweets_final$Date)

write.csv(apply(messi_tweets_final,2,as.character), "/Users/renevillarreal/Desktop/STU/Programming for Data Analytics/messi_tweets_final.csv")

Tweets Final Data Frame

Messi_Final_Project <- read.csv("messi_tweets_final.csv")
Messi_Final_Project

Final Dataset for Analysis


Storing & Extracting from Database

#dbCreateTable(con, "fct_tweets", Messi_Final_Project, row.names = NULL)
#dbWriteTable(con, "fct_tweets", Messi_Final_Project, append = T, row.names = F)

#final_data <- dbReadTable(con, "fct_tweets")
#final_data

Prepare Dataset

final_data <- final_data %>% 
              separate(created_at, into = c("Date", "Time"), sep = " ", convert = TRUE)
Expected 2 pieces. Missing pieces filled with `NA` in 78237 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
final_data$Time <- as.hms(final_data$Time)
final_data$Date <- as.Date(final_data$Date)

final_data <- final_data %>% 
              select(user_id, status_id, Date, Time, screen_name, text, source, display_text_width, reply_to_status_id, is_quote, 
                     favorite_count, retweet_count, hashtags, symbols, lang, name, location, description, protected, followers_count, 
                     friends_count, listed_count, statuses_count, favourites_count, account_created_at, verified, reply_to_status_id)

final_data

Analysis


Problem Statement

Classify if a tweet was made from an Apple device or not given the follower count and friends count. Determine which model is best using Accuracy, Precision, and Recall.

Logistic Regression Model

# Data Prep
final_data_logistic <- mutate(final_data, Source_Class = ifelse(source == "Twitter for iPhone" | source == "Twitter for iPad" | source == "Twitter for Mac" | source == "Twitter for i?S", 
                                                "Apple", "Non_Apple")
                     )

final_data_logistic$Source_Class <- factor(final_data_logistic$Source_Class, levels=c("Non_Apple", "Apple"))


# Sample, Test & Train
set.seed(305)

final_data_logistic$sample <- sample.split(final_data_logistic$Source_Class, SplitRatio = .80)

train_log <- subset(final_data_logistic, sample == TRUE)
test_log <- subset(final_data_logistic, sample == FALSE)


# GLM Model
log_model <- glm(formula = Source_Class ~ followers_count + friends_count,
               data = train_log,
               family = binomial)
glm.fit: fitted probabilities numerically 0 or 1 occurred
# Prediction
test_log$SourceProbability <- predict(log_model, test_log, type = "response")


# Classification
test_log <- mutate(test_log,
               PredictedSource = ifelse(SourceProbability < 0.5, "Non_Apple", "Apple"))

test_log$PredictedSource <- factor(test_log$PredictedSource, levels = c("Non_Apple", "Apple"))


# Metrics
Accuracy_Log <- confusionMatrix(test_log$Source_Class, test_log$PredictedSource)[["overall"]][["Accuracy"]]
Precision_Log <- precision(test_log$Source_Class, test_log$PredictedSource)
Recall_Log <- recall(test_log$Source_Class, test_log$PredictedSource)

cat("\n", "The Accurracy of the Logistic Regression Model is:", Accuracy_Log, "\n")

 The Accurracy of the Logistic Regression Model is: 0.6316227 
cat("The Precision of the Logistic Regression Model is:", Precision_Log, "\n")
The Precision of the Logistic Regression Model is: 1 
cat("The Recall of the Logistic Regression Model is:", Recall_Log, "\n")
The Recall of the Logistic Regression Model is: 0.6316227 

CTREE Model

# Data Prep
final_data_ctree <- mutate(final_data, Source_Class = ifelse(source == "Twitter for iPhone" | source == "Twitter for iPad" | source == "Twitter for Mac" | source == "Twitter for i?S", 
                                                "Apple", "Non_Apple")
                     )

final_data_ctree$Source_Class <- factor(final_data_ctree$Source_Class, levels=c("Non_Apple", "Apple"))


# Sample, Test & Train
set.seed(305)

final_data_ctree$sample <- sample.split(final_data_ctree$Source_Class, SplitRatio = .80)

train_ctree <- subset(final_data_ctree, sample == TRUE)
test_ctree <- subset(final_data_ctree, sample == FALSE)


# CTREE Model
ctree_model <- ctree(formula = Source_Class ~ followers_count + friends_count, train_ctree)


# Plot Model
plot(ctree_model)



# Prediction
Predicted_CTREE <- predict(ctree_model, test_ctree)


# Metrics
Accuracy_CTREE <- confusionMatrix(test_ctree$Source_Class, Predicted_CTREE)[["overall"]][["Accuracy"]]
Precision_CTREE <- precision(test_ctree$Source_Class, Predicted_CTREE)
Recall_CTREE <- recall(test_ctree$Source_Class, Predicted_CTREE)

cat("The Accurracy of the CTREE Model is:", Accuracy_CTREE, "\n")
The Accurracy of the CTREE Model is: 0.6644085 
cat("The Precision of the CTREE Model is:", Precision_CTREE, "\n")
The Precision of the CTREE Model is: 0.9480927 
cat("The Recall of the CTREE Model is:", Recall_CTREE, "\n")
The Recall of the CTREE Model is: 0.6641622 

CART Model

# Data Prep
final_data_cart <- mutate(final_data, Source_Class = ifelse(source == "Twitter for iPhone" | source == "Twitter for iPad" | source == "Twitter for Mac" | source == "Twitter for i?S", 
                                                "Apple", "Non_Apple")
                     )

final_data_cart$Source_Class <- factor(final_data_cart$Source_Class, levels=c("Non_Apple", "Apple"))


# Sample, Test & Train
set.seed(305)

final_data_cart$sample <- sample.split(final_data_cart$Source_Class, SplitRatio = .80)

train_cart <- subset(final_data_cart, sample == TRUE)
test_cart <- subset(final_data_cart, sample == FALSE)


# CART Model
cart_model <- rpart(formula = Source_Class ~ followers_count + friends_count, train_cart)


# Plot Model
rpart.plot(cart_model)



# Prediction
Predicted_CART <- predict(cart_model, test_cart, type = "class")
table(test_cart$Source_Class, Predicted_CART, dnn = c("Actual", "Prediction"))
           Prediction
Actual      Non_Apple Apple
  Non_Apple      9883     0
  Apple          5764     0
# Metrics
Accuracy_CART <- confusionMatrix(test_cart$Source_Class, Predicted_CART)[["overall"]][["Accuracy"]]
Precision_CART <- precision(test_cart$Source_Class, Predicted_CART)
Recall_CART <- recall(test_cart$Source_Class, Predicted_CART)

cat("The Accurracy of the CART Model is:", Accuracy_CART, "\n")
The Accurracy of the CART Model is: 0.6316227 
cat("The Precision of the CART Model is:", Precision_CART, "\n")
The Precision of the CART Model is: 1 
cat("The Recall of the CART Model is:", Recall_CART, "\n")
The Recall of the CART Model is: 0.6316227 

Naive Bayes Model

# Data Prep
final_data_nb <- mutate(final_data, Source_Class = ifelse(source == "Twitter for iPhone" | source == "Twitter for iPad" | source == "Twitter for Mac" | source == "Twitter for i?S", 
                                                "Apple", "Non_Apple")
                     )

final_data_nb$Source_Class <- factor(final_data_nb$Source_Class, levels=c("Non_Apple", "Apple"))


# Sample, Test & Train
set.seed(305)

final_data_nb$sample <- sample.split(final_data_nb$Source_Class, SplitRatio = .80)

train_nb <- subset(final_data_nb, sample == TRUE)
test_nb <- subset(final_data_nb, sample == FALSE)


# Naive Bayes Model
nb_model <- naiveBayes(Source_Class ~ followers_count + friends_count, train_nb)


# Prediction
Predicted_NB <- predict(nb_model, test_nb, type = "class")
table(test_nb$Source_Class, Predicted_NB, dnn = c("Actual", "Prediction"))
           Prediction
Actual      Non_Apple Apple
  Non_Apple       357  9526
  Apple           142  5622
# Metrics
Accuracy_NB <- confusionMatrix(test_nb$Source_Class, Predicted_NB)[["overall"]][["Accuracy"]]
Precision_NB <- precision(test_nb$Source_Class, Predicted_NB)
Recall_NB <- recall(test_nb$Source_Class, Predicted_NB)

cat("The Accurracy of the Naive Bayes Model is:", Accuracy_NB, "\n")
The Accurracy of the Naive Bayes Model is: 0.382118 
cat("The Precision of the Naive Bayes Model is:", Precision_NB, "\n")
The Precision of the Naive Bayes Model is: 0.03612263 
cat("The Recall of the Naive Bayes Model is:", Recall_NB, "\n")
The Recall of the Naive Bayes Model is: 0.7154309 

Conclusion

The CART Model is the best model to use. It has the highest Accuracy and Recall, with the second highest Precision.


Time Series

# Time Series Data Frame
final_data_ts <- messi_tweets_final %>%
                 mutate(source2 = ifelse(source == "Twitter for iPhone" | source == "Twitter for iPad" | source == "Twitter for Mac" | source == "Twitter for i?S", "Apple", "Non_Apple")) %>%
                 filter(source2 == "Apple") %>%
                 select(source, source2, Date, Time) %>%
                 arrange(Date, Time)


# Hour and Date Breakout
final_data_ts$Time <- hour(as.hms(final_data_ts$Time))
final_data_ts$Date <- as.numeric(as.Date(final_data_ts$Date))


# Counting Instances
final_data_ts <- final_data_ts %>%
  arrange(Date, Time) %>%
  group_by(Date, Time) %>%
  summarize(count= n())
`summarise()` regrouping output by 'Date' (override with `.groups` argument)
# Time Series Model
model_ts <-  ts(final_data_ts$count, start = c(18588, 16), end = c(18602, 23), frequency = 24)


# Decomposition
plot(decompose(model_ts))



# ARIMA Model
arima_messi <- auto.arima(model_ts)


# Prediction: 7 days
forecast_ts <- forecast(arima_messi, h = 168)


# Forecast Plot
plot(forecast_ts)

NA
NA
NA
LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCIKYXV0aG9yOiAiUmVuZSBWaWxsYXJyZWFsIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB0cnVlCi0tLQoKIyBQcmVwYXJpbmcgUiBTdHVkaW8KPGJyPgoKIyMgSW5zdGFsbCBMaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodm9zb25TTUwpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KHN5dXpoZXQpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkobGRhKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodG0pCmxpYnJhcnkocnR3ZWV0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGhtcykKbGlicmFyeShjYVRvb2xzKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGUxMDcxKQpsaWJyYXJ5KHJwYXJ0KQpsaWJyYXJ5KHJwYXJ0LnBsb3QpCmxpYnJhcnkocGFydHkpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoYXJ1bGVzKQpgYGAKCiMgQVdTCjxicj4KCiMjIFJEQlMgQ29ubmVjdGlvbgpgYGB7cn0KaG9zdCA9ICJ0ZXh0LWFuYWx5c2lzLmNwa3lwb2oxZ2tjdC51cy1lYXN0LTEucmRzLmFtYXpvbmF3cy5jb20iCnBvcnQgPSAzMzA2CnVzZXIgPSAicnZpbGxhcnJlYWwiCnBhc3N3b3JkID0gIngxMDgwOTg3NyIKCm15X2luc3RhbmNlID0gREJJIDo6IGRiQ29ubmVjdCgKICBSTXlTUUwgOjogTXlTUUwoKSwKICBob3N0ID0gaG9zdCwKICBwb3J0ID0gcG9ydCwKICB1c2VyID0gdXNlciwKICBwYXNzd29yZCA9IHBhc3N3b3JkCikKYGBgCgoKIyMgQ3JlYXRpbmcgRGF0YWJhc2UKYGBge3J9CmRiU2VuZFF1ZXJ5KG15X2luc3RhbmNlLCAiQ1JFQVRFIERBVEFCQVNFIFRXRUVUUyIpCmBgYAoKCiMjIERhdGFiYXNlIENvbm5lY3Rpb24KYGBge3J9CmRibmFtZSA9ICJUV0VFVFMiCgpjb24gPSBEQkkgOjogZGJDb25uZWN0KAogIFJNeVNRTCA6OiBNeVNRTCgpLAogIGRibmFtZSA9IGRibmFtZSwKICBob3N0ID0gaG9zdCwKICBwb3J0ID0gcG9ydCwKICB1c2VyID0gdXNlciwKICBwYXNzd29yZCA9IHBhc3N3b3JkCikKYGBgCgojIFR3aXR0ZXIKCjxicj4KCiMjIEFQSSBDb25uZWN0aW9uCmBgYHtyfQpjb25zdW1lcl9rZXkgPC0gIlI3Z2pmeVpNTE4ydks2aUZsUWYyaGhDUHciCmNvbnN1bWVyX3NlY3JldCA8LSAiWnI1QnF5UEtQemtmTXBBaTNIaWpIazVITkZnTmZmdmlzUERBaVN3ZDlmTHlES0IzSWwiCmFjY2Vzc190b2tlbiA8LSAiMTMyNjMxMjMxNzcwNTkxNjQxNi02ZXN0U2xXZHJLcTI2ek81YmxHb0QxT2FPVmZMQ1YiCmFjY2Vzc19zZWNyZXQgPC0gIkpoNFVnTjgzRVpXVjR3TFFtamtKWmtLZFp6MEJ5TmU1a2wzcTFxSG93YjgxTCIKCnR3aXR0ZXJfdG9rZW4gPC0gY3JlYXRlX3Rva2VuKAogIGFwcCA9ICJQcm9ncmFtbWluZ19EYXRhX0FuYWx5dGljcyIsCiAgY29uc3VtZXJfa2V5ID0gY29uc3VtZXJfa2V5LAogIGNvbnN1bWVyX3NlY3JldCA9IGNvbnN1bWVyX3NlY3JldCwKICBhY2Nlc3NfdG9rZW4gPSBhY2Nlc3NfdG9rZW4sCiAgYWNjZXNzX3NlY3JldCA9IGFjY2Vzc19zZWNyZXQKKQoKc2V0dXBfdHdpdHRlcl9vYXV0aChjb25zdW1lcl9rZXksIGNvbnN1bWVyX3NlY3JldCwgYWNjZXNzX3Rva2VuLCBhY2Nlc3Nfc2VjcmV0KQpgYGAKCiMjIFR3ZWV0cyBFeHRyYWN0aW9uIGFuZCBDU1YKYGBge3J9CiNtZXNzaV90d2VldHM5IDwtIHNlYXJjaF90d2VldHMoIm1lc3NpIE9SIE1FU1NJIE9SIE1lc3NpIiwgbiA9IDE4MDAwLCBsYW5nID0gImVuIiwgaW5jbHVkZV9ydHMgPSBGKQoKbWVzc2lfdHdlZXRzX2ZpbmFsIDwtIGRhdGEuZnJhbWUodW5pcXVlKHJiaW5kKG1lc3NpX3R3ZWV0czMsIG1lc3NpX3R3ZWV0czIsIG1lc3NpX3R3ZWV0cywgbWVzc2lfdHdlZXRzNCwgbWVzc2lfdHdlZXRzNSwgbWVzc2lfdHdlZXRzNiwgbWVzc2lfdHdlZXRzNywgbWVzc2lfdHdlZXRzOCwgbWVzc2lfdHdlZXRzOSkpKQoKbWVzc2lfdHdlZXRzX2ZpbmFsIDwtIG1lc3NpX3R3ZWV0c19maW5hbCAlPiUKICAgICAgICAgICAgICAgICAgICAgIHNlcGFyYXRlKGNyZWF0ZWRfYXQsIGludG8gPSBjKCJEYXRlIiwgIlRpbWUiKSwgc2VwID0gIiAiLCBjb252ZXJ0ID0gVFJVRSkKCm1lc3NpX3R3ZWV0c19maW5hbCRUaW1lIDwtIGFzLmhtcyhtZXNzaV90d2VldHNfZmluYWwkVGltZSkKbWVzc2lfdHdlZXRzX2ZpbmFsJERhdGUgPC0gYXMuRGF0ZShtZXNzaV90d2VldHNfZmluYWwkRGF0ZSkKCndyaXRlLmNzdihhcHBseShtZXNzaV90d2VldHNfZmluYWwsMixhcy5jaGFyYWN0ZXIpLCAiL1VzZXJzL3JlbmV2aWxsYXJyZWFsL0Rlc2t0b3AvU1RVL1Byb2dyYW1taW5nIGZvciBEYXRhIEFuYWx5dGljcy9tZXNzaV90d2VldHNfZmluYWwuY3N2IikKYGBgCgojIyBUd2VldHMgRmluYWwgRGF0YSBGcmFtZQpgYGB7cn0KTWVzc2lfRmluYWxfUHJvamVjdCA8LSByZWFkLmNzdigibWVzc2lfdHdlZXRzX2ZpbmFsLmNzdiIpCk1lc3NpX0ZpbmFsX1Byb2plY3QKYGBgCgojIEZpbmFsIERhdGFzZXQgZm9yIEFuYWx5c2lzCgo8YnI+CgojIyBTdG9yaW5nICYgRXh0cmFjdGluZyBmcm9tIERhdGFiYXNlCmBgYHtyfQojZGJDcmVhdGVUYWJsZShjb24sICJmY3RfdHdlZXRzIiwgTWVzc2lfRmluYWxfUHJvamVjdCwgcm93Lm5hbWVzID0gTlVMTCkKI2RiV3JpdGVUYWJsZShjb24sICJmY3RfdHdlZXRzIiwgTWVzc2lfRmluYWxfUHJvamVjdCwgYXBwZW5kID0gVCwgcm93Lm5hbWVzID0gRikKCiNmaW5hbF9kYXRhIDwtIGRiUmVhZFRhYmxlKGNvbiwgImZjdF90d2VldHMiKQojZmluYWxfZGF0YQpgYGAKCiMjIFByZXBhcmUgRGF0YXNldAoKYGBge3J9CmZpbmFsX2RhdGEgPC0gZmluYWxfZGF0YSAlPiUgCiAgICAgICAgICAgICAgc2VwYXJhdGUoY3JlYXRlZF9hdCwgaW50byA9IGMoIkRhdGUiLCAiVGltZSIpLCBzZXAgPSAiICIsIGNvbnZlcnQgPSBUUlVFKQoKZmluYWxfZGF0YSRUaW1lIDwtIGFzLmhtcyhmaW5hbF9kYXRhJFRpbWUpCmZpbmFsX2RhdGEkRGF0ZSA8LSBhcy5EYXRlKGZpbmFsX2RhdGEkRGF0ZSkKCmZpbmFsX2RhdGEgPC0gZmluYWxfZGF0YSAlPiUgCiAgICAgICAgICAgICAgc2VsZWN0KHVzZXJfaWQsIHN0YXR1c19pZCwgRGF0ZSwgVGltZSwgc2NyZWVuX25hbWUsIHRleHQsIHNvdXJjZSwgZGlzcGxheV90ZXh0X3dpZHRoLCByZXBseV90b19zdGF0dXNfaWQsIGlzX3F1b3RlLCAKICAgICAgICAgICAgICAgICAgICAgZmF2b3JpdGVfY291bnQsIHJldHdlZXRfY291bnQsIGhhc2h0YWdzLCBzeW1ib2xzLCBsYW5nLCBuYW1lLCBsb2NhdGlvbiwgZGVzY3JpcHRpb24sIHByb3RlY3RlZCwgZm9sbG93ZXJzX2NvdW50LCAKICAgICAgICAgICAgICAgICAgICAgZnJpZW5kc19jb3VudCwgbGlzdGVkX2NvdW50LCBzdGF0dXNlc19jb3VudCwgZmF2b3VyaXRlc19jb3VudCwgYWNjb3VudF9jcmVhdGVkX2F0LCB2ZXJpZmllZCwgcmVwbHlfdG9fc3RhdHVzX2lkKQoKZmluYWxfZGF0YQpgYGAKCiMgQW5hbHlzaXMKPGJyPgoKCiMjIFByb2JsZW0gU3RhdGVtZW50CgpDbGFzc2lmeSBpZiBhIHR3ZWV0IHdhcyBtYWRlIGZyb20gYW4gQXBwbGUgZGV2aWNlIG9yIG5vdCBnaXZlbiB0aGUgZm9sbG93ZXIgY291bnQgYW5kIGZyaWVuZHMgY291bnQuIERldGVybWluZSB3aGljaCBtb2RlbCBpcyBiZXN0IHVzaW5nIEFjY3VyYWN5LCBQcmVjaXNpb24sIGFuZCBSZWNhbGwuCgojIyBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsCgpgYGB7cn0KIyBEYXRhIFByZXAKZmluYWxfZGF0YV9sb2dpc3RpYyA8LSBtdXRhdGUoZmluYWxfZGF0YSwgU291cmNlX0NsYXNzID0gaWZlbHNlKHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBob25lIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBhZCIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIE1hYyIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIGk/UyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXBwbGUiLCAiTm9uX0FwcGxlIikKICAgICAgICAgICAgICAgICAgICAgKQoKZmluYWxfZGF0YV9sb2dpc3RpYyRTb3VyY2VfQ2xhc3MgPC0gZmFjdG9yKGZpbmFsX2RhdGFfbG9naXN0aWMkU291cmNlX0NsYXNzLCBsZXZlbHM9YygiTm9uX0FwcGxlIiwgIkFwcGxlIikpCgoKIyBTYW1wbGUsIFRlc3QgJiBUcmFpbgpzZXQuc2VlZCgzMDUpCgpmaW5hbF9kYXRhX2xvZ2lzdGljJHNhbXBsZSA8LSBzYW1wbGUuc3BsaXQoZmluYWxfZGF0YV9sb2dpc3RpYyRTb3VyY2VfQ2xhc3MsIFNwbGl0UmF0aW8gPSAuODApCgp0cmFpbl9sb2cgPC0gc3Vic2V0KGZpbmFsX2RhdGFfbG9naXN0aWMsIHNhbXBsZSA9PSBUUlVFKQp0ZXN0X2xvZyA8LSBzdWJzZXQoZmluYWxfZGF0YV9sb2dpc3RpYywgc2FtcGxlID09IEZBTFNFKQoKCiMgR0xNIE1vZGVsCmxvZ19tb2RlbCA8LSBnbG0oZm9ybXVsYSA9IFNvdXJjZV9DbGFzcyB+IGZvbGxvd2Vyc19jb3VudCArIGZyaWVuZHNfY291bnQsCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9sb2csCiAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKQoKCiMgUHJlZGljdGlvbgp0ZXN0X2xvZyRTb3VyY2VQcm9iYWJpbGl0eSA8LSBwcmVkaWN0KGxvZ19tb2RlbCwgdGVzdF9sb2csIHR5cGUgPSAicmVzcG9uc2UiKQoKCiMgQ2xhc3NpZmljYXRpb24KdGVzdF9sb2cgPC0gbXV0YXRlKHRlc3RfbG9nLAogICAgICAgICAgICAgICBQcmVkaWN0ZWRTb3VyY2UgPSBpZmVsc2UoU291cmNlUHJvYmFiaWxpdHkgPCAwLjUsICJOb25fQXBwbGUiLCAiQXBwbGUiKSkKCnRlc3RfbG9nJFByZWRpY3RlZFNvdXJjZSA8LSBmYWN0b3IodGVzdF9sb2ckUHJlZGljdGVkU291cmNlLCBsZXZlbHMgPSBjKCJOb25fQXBwbGUiLCAiQXBwbGUiKSkKCgojIE1ldHJpY3MKQWNjdXJhY3lfTG9nIDwtIGNvbmZ1c2lvbk1hdHJpeCh0ZXN0X2xvZyRTb3VyY2VfQ2xhc3MsIHRlc3RfbG9nJFByZWRpY3RlZFNvdXJjZSlbWyJvdmVyYWxsIl1dW1siQWNjdXJhY3kiXV0KUHJlY2lzaW9uX0xvZyA8LSBwcmVjaXNpb24odGVzdF9sb2ckU291cmNlX0NsYXNzLCB0ZXN0X2xvZyRQcmVkaWN0ZWRTb3VyY2UpClJlY2FsbF9Mb2cgPC0gcmVjYWxsKHRlc3RfbG9nJFNvdXJjZV9DbGFzcywgdGVzdF9sb2ckUHJlZGljdGVkU291cmNlKQoKY2F0KCJcbiIsICJUaGUgQWNjdXJyYWN5IG9mIHRoZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIGlzOiIsIEFjY3VyYWN5X0xvZywgIlxuIikKY2F0KCJUaGUgUHJlY2lzaW9uIG9mIHRoZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIGlzOiIsIFByZWNpc2lvbl9Mb2csICJcbiIpCmNhdCgiVGhlIFJlY2FsbCBvZiB0aGUgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbCBpczoiLCBSZWNhbGxfTG9nLCAiXG4iKQpgYGAKCiMjIENUUkVFIE1vZGVsCgpgYGB7cn0KIyBEYXRhIFByZXAKZmluYWxfZGF0YV9jdHJlZSA8LSBtdXRhdGUoZmluYWxfZGF0YSwgU291cmNlX0NsYXNzID0gaWZlbHNlKHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBob25lIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBhZCIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIE1hYyIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIGk/UyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXBwbGUiLCAiTm9uX0FwcGxlIikKICAgICAgICAgICAgICAgICAgICAgKQoKZmluYWxfZGF0YV9jdHJlZSRTb3VyY2VfQ2xhc3MgPC0gZmFjdG9yKGZpbmFsX2RhdGFfY3RyZWUkU291cmNlX0NsYXNzLCBsZXZlbHM9YygiTm9uX0FwcGxlIiwgIkFwcGxlIikpCgoKIyBTYW1wbGUsIFRlc3QgJiBUcmFpbgpzZXQuc2VlZCgzMDUpCgpmaW5hbF9kYXRhX2N0cmVlJHNhbXBsZSA8LSBzYW1wbGUuc3BsaXQoZmluYWxfZGF0YV9jdHJlZSRTb3VyY2VfQ2xhc3MsIFNwbGl0UmF0aW8gPSAuODApCgp0cmFpbl9jdHJlZSA8LSBzdWJzZXQoZmluYWxfZGF0YV9jdHJlZSwgc2FtcGxlID09IFRSVUUpCnRlc3RfY3RyZWUgPC0gc3Vic2V0KGZpbmFsX2RhdGFfY3RyZWUsIHNhbXBsZSA9PSBGQUxTRSkKCgojIENUUkVFIE1vZGVsCmN0cmVlX21vZGVsIDwtIGN0cmVlKGZvcm11bGEgPSBTb3VyY2VfQ2xhc3MgfiBmb2xsb3dlcnNfY291bnQgKyBmcmllbmRzX2NvdW50LCB0cmFpbl9jdHJlZSkKCgojIFBsb3QgTW9kZWwKcGxvdChjdHJlZV9tb2RlbCkKCgojIFByZWRpY3Rpb24KUHJlZGljdGVkX0NUUkVFIDwtIHByZWRpY3QoY3RyZWVfbW9kZWwsIHRlc3RfY3RyZWUpCgoKIyBNZXRyaWNzCkFjY3VyYWN5X0NUUkVFIDwtIGNvbmZ1c2lvbk1hdHJpeCh0ZXN0X2N0cmVlJFNvdXJjZV9DbGFzcywgUHJlZGljdGVkX0NUUkVFKVtbIm92ZXJhbGwiXV1bWyJBY2N1cmFjeSJdXQpQcmVjaXNpb25fQ1RSRUUgPC0gcHJlY2lzaW9uKHRlc3RfY3RyZWUkU291cmNlX0NsYXNzLCBQcmVkaWN0ZWRfQ1RSRUUpClJlY2FsbF9DVFJFRSA8LSByZWNhbGwodGVzdF9jdHJlZSRTb3VyY2VfQ2xhc3MsIFByZWRpY3RlZF9DVFJFRSkKCmNhdCgiVGhlIEFjY3VycmFjeSBvZiB0aGUgQ1RSRUUgTW9kZWwgaXM6IiwgQWNjdXJhY3lfQ1RSRUUsICJcbiIpCmNhdCgiVGhlIFByZWNpc2lvbiBvZiB0aGUgQ1RSRUUgTW9kZWwgaXM6IiwgUHJlY2lzaW9uX0NUUkVFLCAiXG4iKQpjYXQoIlRoZSBSZWNhbGwgb2YgdGhlIENUUkVFIE1vZGVsIGlzOiIsIFJlY2FsbF9DVFJFRSwgIlxuIikKYGBgCgojIyBDQVJUIE1vZGVsCgpgYGB7cn0KIyBEYXRhIFByZXAKZmluYWxfZGF0YV9jYXJ0IDwtIG11dGF0ZShmaW5hbF9kYXRhLCBTb3VyY2VfQ2xhc3MgPSBpZmVsc2Uoc291cmNlID09ICJUd2l0dGVyIGZvciBpUGhvbmUiIHwgc291cmNlID09ICJUd2l0dGVyIGZvciBpUGFkIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgTWFjIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaT9TIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcHBsZSIsICJOb25fQXBwbGUiKQogICAgICAgICAgICAgICAgICAgICApCgpmaW5hbF9kYXRhX2NhcnQkU291cmNlX0NsYXNzIDwtIGZhY3RvcihmaW5hbF9kYXRhX2NhcnQkU291cmNlX0NsYXNzLCBsZXZlbHM9YygiTm9uX0FwcGxlIiwgIkFwcGxlIikpCgoKIyBTYW1wbGUsIFRlc3QgJiBUcmFpbgpzZXQuc2VlZCgzMDUpCgpmaW5hbF9kYXRhX2NhcnQkc2FtcGxlIDwtIHNhbXBsZS5zcGxpdChmaW5hbF9kYXRhX2NhcnQkU291cmNlX0NsYXNzLCBTcGxpdFJhdGlvID0gLjgwKQoKdHJhaW5fY2FydCA8LSBzdWJzZXQoZmluYWxfZGF0YV9jYXJ0LCBzYW1wbGUgPT0gVFJVRSkKdGVzdF9jYXJ0IDwtIHN1YnNldChmaW5hbF9kYXRhX2NhcnQsIHNhbXBsZSA9PSBGQUxTRSkKCgojIENBUlQgTW9kZWwKY2FydF9tb2RlbCA8LSBycGFydChmb3JtdWxhID0gU291cmNlX0NsYXNzIH4gZm9sbG93ZXJzX2NvdW50ICsgZnJpZW5kc19jb3VudCwgdHJhaW5fY2FydCkKCgojIFBsb3QgTW9kZWwKcnBhcnQucGxvdChjYXJ0X21vZGVsKQoKCiMgUHJlZGljdGlvbgpQcmVkaWN0ZWRfQ0FSVCA8LSBwcmVkaWN0KGNhcnRfbW9kZWwsIHRlc3RfY2FydCwgdHlwZSA9ICJjbGFzcyIpCnRhYmxlKHRlc3RfY2FydCRTb3VyY2VfQ2xhc3MsIFByZWRpY3RlZF9DQVJULCBkbm4gPSBjKCJBY3R1YWwiLCAiUHJlZGljdGlvbiIpKQoKCiMgTWV0cmljcwpBY2N1cmFjeV9DQVJUIDwtIGNvbmZ1c2lvbk1hdHJpeCh0ZXN0X2NhcnQkU291cmNlX0NsYXNzLCBQcmVkaWN0ZWRfQ0FSVClbWyJvdmVyYWxsIl1dW1siQWNjdXJhY3kiXV0KUHJlY2lzaW9uX0NBUlQgPC0gcHJlY2lzaW9uKHRlc3RfY2FydCRTb3VyY2VfQ2xhc3MsIFByZWRpY3RlZF9DQVJUKQpSZWNhbGxfQ0FSVCA8LSByZWNhbGwodGVzdF9jYXJ0JFNvdXJjZV9DbGFzcywgUHJlZGljdGVkX0NBUlQpCgpjYXQoIlRoZSBBY2N1cnJhY3kgb2YgdGhlIENBUlQgTW9kZWwgaXM6IiwgQWNjdXJhY3lfQ0FSVCwgIlxuIikKY2F0KCJUaGUgUHJlY2lzaW9uIG9mIHRoZSBDQVJUIE1vZGVsIGlzOiIsIFByZWNpc2lvbl9DQVJULCAiXG4iKQpjYXQoIlRoZSBSZWNhbGwgb2YgdGhlIENBUlQgTW9kZWwgaXM6IiwgUmVjYWxsX0NBUlQsICJcbiIpCmBgYAoKIyMgTmFpdmUgQmF5ZXMgTW9kZWwKCmBgYHtyfQojIERhdGEgUHJlcApmaW5hbF9kYXRhX25iIDwtIG11dGF0ZShmaW5hbF9kYXRhLCBTb3VyY2VfQ2xhc3MgPSBpZmVsc2Uoc291cmNlID09ICJUd2l0dGVyIGZvciBpUGhvbmUiIHwgc291cmNlID09ICJUd2l0dGVyIGZvciBpUGFkIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgTWFjIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaT9TIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcHBsZSIsICJOb25fQXBwbGUiKQogICAgICAgICAgICAgICAgICAgICApCgpmaW5hbF9kYXRhX25iJFNvdXJjZV9DbGFzcyA8LSBmYWN0b3IoZmluYWxfZGF0YV9uYiRTb3VyY2VfQ2xhc3MsIGxldmVscz1jKCJOb25fQXBwbGUiLCAiQXBwbGUiKSkKCgojIFNhbXBsZSwgVGVzdCAmIFRyYWluCnNldC5zZWVkKDMwNSkKCmZpbmFsX2RhdGFfbmIkc2FtcGxlIDwtIHNhbXBsZS5zcGxpdChmaW5hbF9kYXRhX25iJFNvdXJjZV9DbGFzcywgU3BsaXRSYXRpbyA9IC44MCkKCnRyYWluX25iIDwtIHN1YnNldChmaW5hbF9kYXRhX25iLCBzYW1wbGUgPT0gVFJVRSkKdGVzdF9uYiA8LSBzdWJzZXQoZmluYWxfZGF0YV9uYiwgc2FtcGxlID09IEZBTFNFKQoKCiMgTmFpdmUgQmF5ZXMgTW9kZWwKbmJfbW9kZWwgPC0gbmFpdmVCYXllcyhTb3VyY2VfQ2xhc3MgfiBmb2xsb3dlcnNfY291bnQgKyBmcmllbmRzX2NvdW50LCB0cmFpbl9uYikKCgojIFByZWRpY3Rpb24KUHJlZGljdGVkX05CIDwtIHByZWRpY3QobmJfbW9kZWwsIHRlc3RfbmIsIHR5cGUgPSAiY2xhc3MiKQp0YWJsZSh0ZXN0X25iJFNvdXJjZV9DbGFzcywgUHJlZGljdGVkX05CLCBkbm4gPSBjKCJBY3R1YWwiLCAiUHJlZGljdGlvbiIpKQoKCiMgTWV0cmljcwpBY2N1cmFjeV9OQiA8LSBjb25mdXNpb25NYXRyaXgodGVzdF9uYiRTb3VyY2VfQ2xhc3MsIFByZWRpY3RlZF9OQilbWyJvdmVyYWxsIl1dW1siQWNjdXJhY3kiXV0KUHJlY2lzaW9uX05CIDwtIHByZWNpc2lvbih0ZXN0X25iJFNvdXJjZV9DbGFzcywgUHJlZGljdGVkX05CKQpSZWNhbGxfTkIgPC0gcmVjYWxsKHRlc3RfbmIkU291cmNlX0NsYXNzLCBQcmVkaWN0ZWRfTkIpCgpjYXQoIlRoZSBBY2N1cnJhY3kgb2YgdGhlIE5haXZlIEJheWVzIE1vZGVsIGlzOiIsIEFjY3VyYWN5X05CLCAiXG4iKQpjYXQoIlRoZSBQcmVjaXNpb24gb2YgdGhlIE5haXZlIEJheWVzIE1vZGVsIGlzOiIsIFByZWNpc2lvbl9OQiwgIlxuIikKY2F0KCJUaGUgUmVjYWxsIG9mIHRoZSBOYWl2ZSBCYXllcyBNb2RlbCBpczoiLCBSZWNhbGxfTkIsICJcbiIpCmBgYAoKIyMgQ29uY2x1c2lvbgpUaGUgQ0FSVCBNb2RlbCBpcyB0aGUgYmVzdCBtb2RlbCB0byB1c2UuIEl0IGhhcyB0aGUgaGlnaGVzdCBBY2N1cmFjeSBhbmQgUmVjYWxsLCB3aXRoIHRoZSBzZWNvbmQgaGlnaGVzdCBQcmVjaXNpb24uCgo8YnI+CgojIFRpbWUgU2VyaWVzCgpgYGB7cn0KIyBUaW1lIFNlcmllcyBEYXRhIEZyYW1lCmZpbmFsX2RhdGFfdHMgPC0gbWVzc2lfdHdlZXRzX2ZpbmFsICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UyID0gaWZlbHNlKHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBob25lIiB8IHNvdXJjZSA9PSAiVHdpdHRlciBmb3IgaVBhZCIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIE1hYyIgfCBzb3VyY2UgPT0gIlR3aXR0ZXIgZm9yIGk/UyIsICJBcHBsZSIsICJOb25fQXBwbGUiKSkgJT4lCiAgICAgICAgICAgICAgICAgZmlsdGVyKHNvdXJjZTIgPT0gIkFwcGxlIikgJT4lCiAgICAgICAgICAgICAgICAgc2VsZWN0KHNvdXJjZSwgc291cmNlMiwgRGF0ZSwgVGltZSkgJT4lCiAgICAgICAgICAgICAgICAgYXJyYW5nZShEYXRlLCBUaW1lKQoKCiMgSG91ciBhbmQgRGF0ZSBCcmVha291dApmaW5hbF9kYXRhX3RzJFRpbWUgPC0gaG91cihhcy5obXMoZmluYWxfZGF0YV90cyRUaW1lKSkKZmluYWxfZGF0YV90cyREYXRlIDwtIGFzLm51bWVyaWMoYXMuRGF0ZShmaW5hbF9kYXRhX3RzJERhdGUpKQoKCiMgQ291bnRpbmcgSW5zdGFuY2VzCmZpbmFsX2RhdGFfdHMgPC0gZmluYWxfZGF0YV90cyAlPiUKICBhcnJhbmdlKERhdGUsIFRpbWUpICU+JQogIGdyb3VwX2J5KERhdGUsIFRpbWUpICU+JQogIHN1bW1hcml6ZShjb3VudD0gbigpKQoKCiMgVGltZSBTZXJpZXMgTW9kZWwKbW9kZWxfdHMgPC0gIHRzKGZpbmFsX2RhdGFfdHMkY291bnQsIHN0YXJ0ID0gYygxODU4OCwgMTYpLCBlbmQgPSBjKDE4NjAyLCAyMyksIGZyZXF1ZW5jeSA9IDI0KQoKCiMgRGVjb21wb3NpdGlvbgpwbG90KGRlY29tcG9zZShtb2RlbF90cykpCgoKIyBBUklNQSBNb2RlbAphcmltYV9tZXNzaSA8LSBhdXRvLmFyaW1hKG1vZGVsX3RzKQoKCiMgUHJlZGljdGlvbjogNyBkYXlzCmZvcmVjYXN0X3RzIDwtIGZvcmVjYXN0KGFyaW1hX21lc3NpLCBoID0gMTY4KQoKCiMgRm9yZWNhc3QgUGxvdApwbG90KGZvcmVjYXN0X3RzKQoKCgpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCg==